package org.gw.ylc.base.data;

import antlr.RecognitionException;
import antlr.TokenStreamException;
import antlr.collections.AST;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.QueryException;
import org.hibernate.ScrollableResults;
import org.hibernate.engine.query.spi.EntityGraphQueryHint;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.event.spi.EventSource;
import org.hibernate.hql.internal.antlr.HqlTokenTypes;
import org.hibernate.hql.internal.ast.HqlParser;
import org.hibernate.hql.internal.ast.QueryTranslatorImpl;
import org.hibernate.hql.internal.ast.util.ASTPrinter;
import org.hibernate.hql.spi.FilterTranslator;
import org.hibernate.hql.spi.ParameterTranslations;
import org.hibernate.type.Type;

import java.io.Serializable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

@SuppressWarnings("rawtypes")
public class PermissionedQueryTranslator implements FilterTranslator {

	protected Map replacements;
	protected boolean shallow;
	protected String queryIdentifier;
	protected String hql;
	protected boolean shallowQuery;
	protected Map enabledFilters;
	protected SessionFactoryImplementor factory;
	protected EntityGraphQueryHint entityGraphQueryHint;
	protected String collectionRole;
	protected QueryTranslatorImpl originTranslator;
	protected QueryTranslatorImpl currentTranslator;

	public PermissionedQueryTranslator(String queryIdentifier, String query, Map enabledFilters,
			SessionFactoryImplementor factory) {
		this(queryIdentifier, query, enabledFilters, factory, null);
	}

	public PermissionedQueryTranslator(String queryIdentifier, String query, Map enabledFilters,
			SessionFactoryImplementor factory, EntityGraphQueryHint entityGraphQueryHint) {
		this.queryIdentifier = queryIdentifier;
		this.hql = query;
		this.shallowQuery = false;
		this.enabledFilters = enabledFilters;
		this.factory = factory;
		this.entityGraphQueryHint = entityGraphQueryHint;
		this.originTranslator = new QueryTranslatorImpl(queryIdentifier, query, enabledFilters, factory,
				entityGraphQueryHint);
		//EntityPersister entityPersister = factory.getEntityPersister("Volunteer");
	}

	private static final ASTPrinter HQL_TOKEN_PRINTER = new ASTPrinter(HqlTokenTypes.class);

	@Override
	public void compile(Map replacements, boolean shallow) throws QueryException, MappingException {
		this.replacements = replacements;
		this.shallow = shallow;
		originTranslator.compile(replacements, shallow);
		Set<Serializable> querySpaces = this.getQuerySpaces();
		System.out.println(querySpaces);
		HqlParser parser = HqlParser.getInstance(hql);
		parser.setFilter(true);
		try {
			parser.statement();
		} catch (RecognitionException | TokenStreamException e) {
			e.printStackTrace();
		}
		final AST hqlAst = parser.getAST();
		//System.out.println(hql);
		//System.out.println(HQL_TOKEN_PRINTER.showAsString(hqlAst, "--- HQL AST ---"));
	}

	@Override
	public void compile(String collectionRole, Map replacements, boolean shallow)
			throws QueryException, MappingException {
		this.collectionRole = collectionRole;
		this.replacements = replacements;
		this.shallow = shallow;
		originTranslator.compile(collectionRole, replacements, shallow);
	}

	protected QueryTranslatorImpl getCurrentTranslator() {
		return currentTranslator != null ? currentTranslator : originTranslator;
	}

	@Override
	public List list(SessionImplementor session, QueryParameters queryParameters) throws HibernateException {
		return getCurrentTranslator().list(session, queryParameters);
	}

	@Override
	public Iterator iterate(QueryParameters queryParameters, EventSource session) throws HibernateException {
		return getCurrentTranslator().iterate(queryParameters, session);
	}

	@Override
	public ScrollableResults scroll(QueryParameters queryParameters, SessionImplementor session)
			throws HibernateException {
		return getCurrentTranslator().scroll(queryParameters, session);
	}

	@Override
	public int executeUpdate(QueryParameters queryParameters, SessionImplementor session) throws HibernateException {
		return getCurrentTranslator().executeUpdate(queryParameters, session);
	}

	@Override
	public Set<Serializable> getQuerySpaces() {
		return getCurrentTranslator().getQuerySpaces();
	}

	@Override
	public String getQueryIdentifier() {
		return getCurrentTranslator().getQueryIdentifier();
	}

	@Override
	public String getSQLString() {
		return getCurrentTranslator().getSQLString();
	}

	@Override
	public List<String> collectSqlStrings() {
		return getCurrentTranslator().collectSqlStrings();
	}

	@Override
	public String getQueryString() {
		return getCurrentTranslator().getQueryString();
	}

	@Override
	public Map getEnabledFilters() {
		return getCurrentTranslator().getEnabledFilters();
	}

	@Override
	public Type[] getReturnTypes() {
		return getCurrentTranslator().getReturnTypes();
	}

	@Override
	public String[] getReturnAliases() {
		return getCurrentTranslator().getReturnAliases();
	}

	@Override
	public String[][] getColumnNames() {
		return getCurrentTranslator().getColumnNames();
	}

	@Override
	public ParameterTranslations getParameterTranslations() {
		return getCurrentTranslator().getParameterTranslations();
	}

	@Override
	public void validateScrollability() throws HibernateException {
		getCurrentTranslator().validateScrollability();
	}

	@Override
	public boolean containsCollectionFetches() {
		return getCurrentTranslator().containsCollectionFetches();
	}

	@Override
	public boolean isManipulationStatement() {
		return getCurrentTranslator().isManipulationStatement();
	}

	@Override
	public Class getDynamicInstantiationResultType() {
		return getCurrentTranslator().getDynamicInstantiationResultType();
	}

}
